#pragma once

#include "bezier.h"
#include "poly_bezier_builder_base.h"
#include <boost/shared_ptr.hpp>

namespace outline {

template <typename R>
struct grand_params : poly_bezier_builder_params<R> 
{
	unsigned max_junctions;
	R penalty_for_each_junction;
};

template <typename T, typename R = typename type_traits<T>::real_type>
class grand_poly_bezier_builder : public poly_bezier_builder_base<T, R>
{
public:
	void reset(nodes_type const & polyline);
	void set_params(grand_params<R> const & params);
	void inspect_greater_bezier_length();
	uint calced_length() const
		{ return length_; }
	uint max_piece_length() const
		{ return size_ + 1; }
	bool all_length_inspected() const
		{ return length_ >= size_ + 1; }
	virtual R select_best(index_vector_type & ivec);
	virtual grand_params<R> const & get_params() const
		{ return params_; }
	estimation_type const & inline_get_estimation(uint begin, uint len) const;
	virtual estimation_type const & get_estimation(uint begin, uint len, uint) const;
	virtual void get_junction_types(index_vector_type const & ivec, std::vector<junc_type> & junc) const;
private:
	grand_params<R> params_;
	uint length_; ///< all bezier curves with this length (including start and finish nodes) are inspected (max length_ = size+1)
private:
	/// size_ * (length_-3) elements
	/// estimations_[b][l].d says that
	/// piece of nodes starting from node b and ending (including) at node b+l+5 may
	/// be approximated with that discrepancy;
	/// very probably that satisfied estimations_[b][0].d = 0 (len=4) for all b's
	estimation_matrix_type estimations_; 

	struct junction_layer {
		junction_layer(uint size, uint minl, uint maxl);
		uint l_min, l_max;
		step_matrix_type matrix; //first index - piece beginning, second index - length: (l_min;l_max]
		step_type & operator() (uint begin, uint len) { return matrix[begin][len - l_min]; }
		step_type const & operator() (uint begin, uint len) const { return matrix[begin][len - l_min]; }
	};
	typedef boost::shared_ptr<junction_layer> junction_layer_sptr;

	// brick constructed during select_best(...) method execution;
	// brick[j].matrix[b][l] says that
	// pieace of nodes starting from node b and ending (including) at node b+l+l_min and
	// containing j junctions may be approximated with that discrepancy;
	// first layer of brick_type is a copy of estimations_
	typedef std::vector<junction_layer_sptr> brick_type; //size of vector is params_.max_junctions-1
};

//inlines

template <typename T, typename R>
inline typename grand_poly_bezier_builder<T,R>::estimation_type const & 
grand_poly_bezier_builder<T,R>::inline_get_estimation(uint begin, uint len) const
{
	assert(begin < size_);
	assert(len >= 4 && len <= length_);
	return estimations_[begin][len-4];
}

} //namespace outline
